package com.iacrqq.sedaf.application;

import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.iacrqq.sedaf.application.adaptive.ApplicationAdjuster;
import com.iacrqq.sedaf.config.Configuration;
import com.iacrqq.sedaf.event.EventDispatcher;
import com.iacrqq.sedaf.queue.Output;
import com.iacrqq.sedaf.queue.Queue;
import com.iacrqq.sedaf.queue.adaptive.QueueAdjuster;
import com.iacrqq.sedaf.stage.Stage;
import com.iacrqq.sedaf.stage.adaptive.StageAdjuster;

/**
 * 
 * @author sihai
 * 
 */
public class DefaultApplication implements Application
{
	
	private static Log logger = LogFactory.getLog(DefaultApplication.class);
	
	private String name;
	private Configuration configuration;
	private List<Queue> queueList = new LinkedList<Queue>();
	private List<Stage> stageList = new LinkedList<Stage>();
	
	private Map<Queue, Stage> input2StageMap = new HashMap<Queue, Stage>();
	private Map<Queue, Stage> output2StageMap = new HashMap<Queue, Stage>();

	private ApplicationAdjuster applicationAdjuster;
	
	private EventDispatcher eventDispatcher;

	@Override
	public void init(Configuration config) throws Exception
	{
		input2StageMap = new HashMap<Queue, Stage>();
		output2StageMap = new HashMap<Queue, Stage>();
		
		// init queue
		for (Queue queue : queueList)
		{
			queue.init(config);
		}
		// init stage
		for (Stage stage : stageList)
		{
			stage.setEventDispatcher(eventDispatcher);
			stage.init(config);
			
			input2StageMap.put((Queue)stage.getInput(), stage);
			for(Output output : stage.getOutputs())
			{
				output2StageMap.put((Queue)output, stage);
			}
		}
		
	}

	@Override
	public void destroy() throws Exception
	{
		// init queue
		for (Queue queue : queueList)
		{
			queue.destroy();
		}
		// init stage
		for (Stage stage : stageList)
		{
			stage.destroy();
		}
	}

	@Override
	public String getName()
	{
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public void setName(String name)
	{
		this.name = name;
	}

	@Override
	public void setConfiguration(Configuration config)
	{
		this.configuration = config;
	}
	
	@Override
	public void setEventDispatcher(EventDispatcher eventDispatcher)
	{
		this.eventDispatcher = eventDispatcher;
	}

	@Override
	public Configuration getConfiguration()
	{
		return this.configuration;
	}

	@Override
	public void pause()
	{
		// TODO Auto-generated method stub

	}

	@Override
	public void start()
	{
		for (Stage stage : stageList)
		{
			stage.start();
		}
	}

	@Override
	public void stop()
	{
		for (Stage stage : stageList)
		{
			stage.stop();
		}
	}

	@Override
	public void addQueue(Queue queue)
	{
		queueList.add(queue);
	}

	@Override
	public void addStage(Stage stage)
	{
		stageList.add(stage);
	}

	@Override
	public void startAdaptiveAjust()
	{
		try
		{
			applicationAdjuster = new ApplicationAdjuster();
			
			applicationAdjuster.init(configuration);
			// init queue
			for (Queue queue : queueList)
			{
				applicationAdjuster.addQueueAdjuster(new QueueAdjuster(queue));
			}
			// init stage
			for (Stage stage : stageList)
			{
				applicationAdjuster.addStageAdjuster(new StageAdjuster(stage, ApplicationAdjuster.DEFAULT_ADJUST_HISTORY, ApplicationAdjuster.DEFAULT_ADJUST_INTERVAL));
			}
			this.applicationAdjuster.start();
		}
		catch(Exception e)
		{
			logger.warn(new StringBuilder(name).append("'s applicationAdjuster start failed."));
		}
	}
	
	@Override
	public void stopAdaptiveAjust()
	{
		this.applicationAdjuster.stop();
	}

	@Override
	public void setAdjuster(ApplicationAdjuster adjuster)
	{
		this.applicationAdjuster = adjuster;
	}
}
